"""
优化版智能招聘助手Agent
解决原代码中的硬编码、错误处理、扩展性等问题
"""

import re
import logging
import json
from dataclasses import dataclass, asdict
from typing import List, Dict, Optional, Any, Tuple
from enum import Enum
from functools import lru_cache

from langchain.agents import ZeroShotAgent, AgentExecutor
from langchain.chains.llm import LLMChain
from langchain.chat_models import init_chat_model
from langchain_core.prompts import PromptTemplate
from langchain_core.tools import tool

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class MatchLevel(Enum):
    """匹配等级枚举"""
    HIGH = "high"      # 高匹配 (>=70分)
    MEDIUM = "medium"  # 中等匹配 (50-69分)
    LOW = "low"        # 低匹配 (<50分)


@dataclass
class ResumeInfo:
    """简历信息数据类"""
    name: str
    experience_years: int
    skills: List[str]
    projects: List[str]
    education: Optional[str] = None
    location: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    
    def to_dict(self) -> Dict:
        return asdict(self)


@dataclass
class MatchResult:
    """匹配结果数据类"""
    score: float
    level: MatchLevel
    matched_skills: List[str]
    missing_skills: List[str]
    experience_match: bool
    recommendation: str
    confidence: float  # 匹配置信度 0-1


@dataclass
class JobConfig:
    """岗位配置数据类"""
    job_title: str
    required_skills: List[str]
    preferred_skills: List[str]
    min_experience: int
    max_experience: int
    skill_weights: Dict[str, float]
    experience_weight: float
    threshold_scores: Dict[MatchLevel, float]
    job_description: str


class RecruitmentConfig:
    """招聘配置管理类"""
    
    def __init__(self):
        self.job_configs = self._load_default_configs()
    
    def _load_default_configs(self) -> Dict[str, JobConfig]:
        """加载默认岗位配置"""
        return {
            "ai_agent_engineer": JobConfig(
                job_title="AI Agent开发工程师",
                required_skills=["Python", "LangChain", "Agent开发"],
                preferred_skills=["大模型微调", "RAG", "工具调用", "向量数据库"],
                min_experience=3,
                max_experience=8,
                skill_weights={
                    "Python": 0.25,
                    "LangChain": 0.30,
                    "Agent开发": 0.20,
                    "大模型微调": 0.15,
                    "RAG": 0.10
                },
                experience_weight=0.3,
                threshold_scores={
                    MatchLevel.HIGH: 70,
                    MatchLevel.MEDIUM: 50,
                    MatchLevel.LOW: 0
                },
                job_description="负责AI Agent系统的设计、开发和优化"
            ),
            "python_developer": JobConfig(
                job_title="Python开发工程师",
                required_skills=["Python", "Django", "Flask"],
                preferred_skills=["MySQL", "Redis", "Docker", "微服务"],
                min_experience=2,
                max_experience=6,
                skill_weights={
                    "Python": 0.30,
                    "Django": 0.25,
                    "Flask": 0.20,
                    "MySQL": 0.15,
                    "Redis": 0.10
                },
                experience_weight=0.25,
                threshold_scores={
                    MatchLevel.HIGH: 75,
                    MatchLevel.MEDIUM: 55,
                    MatchLevel.LOW: 0
                },
                job_description="负责后端系统开发和维护"
            )
        }
    
    def get_job_config(self, job_type: str) -> JobConfig:
        """获取岗位配置"""
        if job_type not in self.job_configs:
            raise ValueError(f"未找到岗位配置: {job_type}")
        return self.job_configs[job_type]
    
    def add_job_config(self, job_type: str, config: JobConfig):
        """添加新岗位配置"""
        self.job_configs[job_type] = config


class EnhancedResumeParser:
    """增强版简历解析器"""
    
    def __init__(self):
        self.skill_keywords = {
            "Python": ["python", "py", "django", "flask", "fastapi"],
            "LangChain": ["langchain", "lang chain", "langchain框架"],
            "Agent开发": ["agent", "智能体", "代理", "助手"],
            "大模型微调": ["微调", "finetune", "fine-tune", "模型训练"],
            "RAG": ["rag", "检索增强", "向量检索"],
            "工具调用": ["工具调用", "function calling", "tool calling"]
        }
    
    @lru_cache(maxsize=100)
    def parse_resume(self, resume_text: str) -> ResumeInfo:
        """解析简历文本，提取结构化信息"""
        try:
            logger.info(f"开始解析简历，长度: {len(resume_text)}")
            
            # 提取基本信息
            name = self._extract_name(resume_text)
            experience_years = self._extract_experience(resume_text)
            skills = self._extract_skills(resume_text)
            projects = self._extract_projects(resume_text)
            
            resume_info = ResumeInfo(
                name=name,
                experience_years=experience_years,
                skills=skills,
                projects=projects
            )
            
            logger.info(f"简历解析完成: {name}, {experience_years}年经验, {len(skills)}项技能")
            return resume_info
            
        except Exception as e:
            logger.error(f"简历解析失败: {e}")
            # 返回默认值而不是抛出异常
            return ResumeInfo(
                name="未知",
                experience_years=0,
                skills=[],
                projects=[]
            )
    
    def _extract_name(self, text: str) -> str:
        """提取姓名"""
        patterns = [
            r'姓名[：:]\s*([^\n\r]+)',
            r'姓名[：:]\s*([^\s]+)',
            r'name[：:]\s*([^\n\r]+)',
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                return match.group(1).strip()
        
        return "未知"
    
    def _extract_experience(self, text: str) -> int:
        """提取工作年限"""
        patterns = [
            r'(\d+)\s*年\s*经验',
            r'工作经验[：:]\s*(\d+)\s*年',
            r'(\d+)\s*years?\s*experience',
            r'(\d+)\s*年\s*工作'
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                return int(match.group(1))
        
        return 0
    
    def _extract_skills(self, text: str) -> List[str]:
        """提取技能标签"""
        found_skills = []
        
        for skill, keywords in self.skill_keywords.items():
            for keyword in keywords:
                if keyword.lower() in text.lower():
                    found_skills.append(skill)
                    break
        
        return list(set(found_skills))  # 去重
    
    def _extract_projects(self, text: str) -> List[str]:
        """提取项目经验"""
        project_patterns = [
            r'项目[：:]([^\n\r]+)',
            r'项目经验[：:]([^\n\r]+)',
            r'主要项目[：:]([^\n\r]+)'
        ]
        
        projects = []
        for pattern in project_patterns:
            matches = re.findall(pattern, text, re.IGNORECASE)
            projects.extend(matches)
        
        return [p.strip() for p in projects if p.strip()]


class EnhancedJobMatcher:
    """增强版岗位匹配器"""
    
    def __init__(self, config_manager: RecruitmentConfig):
        self.config_manager = config_manager
    
    def calculate_match(self, resume_info: ResumeInfo, job_type: str) -> MatchResult:
        """计算简历与岗位的匹配度"""
        try:
            job_config = self.config_manager.get_job_config(job_type)
            
            # 计算技能匹配度
            skill_score, matched_skills, missing_skills = self._calculate_skill_match(
                resume_info.skills, job_config
            )
            
            # 计算经验匹配度
            experience_score, experience_match = self._calculate_experience_match(
                resume_info.experience_years, job_config
            )
            
            # 计算综合分数
            total_score = (
                skill_score * (1 - job_config.experience_weight) +
                experience_score * job_config.experience_weight
            )
            
            # 确定匹配等级
            level = self._determine_match_level(total_score, job_config)
            
            # 生成建议
            recommendation = self._generate_recommendation(
                level, matched_skills, missing_skills, experience_match
            )
            
            # 计算置信度
            confidence = self._calculate_confidence(
                len(matched_skills), len(missing_skills), experience_match
            )
            
            return MatchResult(
                score=total_score,
                level=level,
                matched_skills=matched_skills,
                missing_skills=missing_skills,
                experience_match=experience_match,
                recommendation=recommendation,
                confidence=confidence
            )
            
        except Exception as e:
            logger.error(f"岗位匹配计算失败: {e}")
            return MatchResult(
                score=0,
                level=MatchLevel.LOW,
                matched_skills=[],
                missing_skills=[],
                experience_match=False,
                recommendation="匹配计算失败，请检查简历格式",
                confidence=0.0
            )
    
    def _calculate_skill_match(self, skills: List[str], config: JobConfig) -> Tuple[float, List[str], List[str]]:
        """计算技能匹配度"""
        matched_skills = []
        missing_skills = []
        total_weight = 0.0
        matched_weight = 0.0
        
        # 检查必需技能
        for skill in config.required_skills:
            if skill in skills:
                matched_skills.append(skill)
                weight = config.skill_weights.get(skill, 0.1)
                matched_weight += weight
            else:
                missing_skills.append(skill)
            total_weight += config.skill_weights.get(skill, 0.1)
        
        # 检查优先技能
        for skill in config.preferred_skills:
            if skill in skills and skill not in matched_skills:
                matched_skills.append(skill)
                weight = config.skill_weights.get(skill, 0.05)
                matched_weight += weight
            total_weight += config.skill_weights.get(skill, 0.05)
        
        skill_score = (matched_weight / total_weight * 100) if total_weight > 0 else 0
        return skill_score, matched_skills, missing_skills
    
    def _calculate_experience_match(self, experience_years: int, config: JobConfig) -> Tuple[float, bool]:
        """计算经验匹配度"""
        if experience_years < config.min_experience:
            return 0, False
        elif experience_years > config.max_experience:
            return 80, True  # 经验过丰富，适当降分
        else:
            # 在合理范围内，按比例给分
            range_size = config.max_experience - config.min_experience
            if range_size == 0:
                return 100, True
            
            position = (experience_years - config.min_experience) / range_size
            score = 60 + (position * 40)  # 60-100分
            return score, True
    
    def _determine_match_level(self, score: float, config: JobConfig) -> MatchLevel:
        """确定匹配等级"""
        if score >= config.threshold_scores[MatchLevel.HIGH]:
            return MatchLevel.HIGH
        elif score >= config.threshold_scores[MatchLevel.MEDIUM]:
            return MatchLevel.MEDIUM
        else:
            return MatchLevel.LOW
    
    def _generate_recommendation(self, level: MatchLevel, matched_skills: List[str], 
                                missing_skills: List[str], experience_match: bool) -> str:
        """生成匹配建议"""
        if level == MatchLevel.HIGH:
            return f"高度匹配！技能匹配度优秀，建议优先安排面试。匹配技能：{', '.join(matched_skills)}"
        elif level == MatchLevel.MEDIUM:
            return f"中等匹配，技能部分符合要求。建议进一步沟通了解。匹配技能：{', '.join(matched_skills)}"
        else:
            missing_info = f"缺失技能：{', '.join(missing_skills)}" if missing_skills else ""
            return f"匹配度较低，{missing_info}。建议了解候选人学习意愿和潜力。"
    
    def _calculate_confidence(self, matched_count: int, missing_count: int, experience_match: bool) -> float:
        """计算匹配置信度"""
        total_skills = matched_count + missing_count
        if total_skills == 0:
            return 0.0
        
        skill_confidence = matched_count / total_skills
        experience_confidence = 1.0 if experience_match else 0.5
        
        return (skill_confidence * 0.7 + experience_confidence * 0.3)


class EnhancedMessageGenerator:
    """增强版话术生成器"""
    
    def __init__(self):
        self.templates = {
            MatchLevel.HIGH: {
                "greeting": "您好！",
                "match_info": "您的简历与我司「{job_title}」岗位匹配度达{score}分，技能和经验高度符合要求。",
                "action": "我们希望邀请您{time}进行线上面试，主要沟通项目细节和技术深度。",
                "closing": "请问您方便吗？期待与您的进一步沟通！"
            },
            MatchLevel.MEDIUM: {
                "greeting": "您好！",
                "match_info": "您的简历与我司「{job_title}」岗位匹配度为{score}分，技能有部分重合。",
                "action": "我们想进一步了解您的技术背景，方便的话可以简单沟通一下。",
                "closing": "您看什么时候方便？"
            },
            MatchLevel.LOW: {
                "greeting": "您好！",
                "match_info": "感谢您对我司「{job_title}」岗位的关注。",
                "action": "虽然当前匹配度不高，但我们想了解您是否有学习相关技术的计划。",
                "closing": "若方便可简单沟通补充信息，谢谢！"
            }
        }
    
    def generate_message(self, match_result: MatchResult, job_title: str, 
                        candidate_name: str = "候选人") -> str:
        """生成个性化沟通话术"""
        try:
            template = self.templates[match_result.level]
            
            # 个性化问候
            greeting = f"{candidate_name}，{template['greeting']}"
            
            # 匹配信息
            match_info = template['match_info'].format(
                job_title=job_title,
                score=int(match_result.score)
            )
            
            # 行动建议
            action = template['action']
            if match_result.level == MatchLevel.HIGH:
                action = action.format(time="本周三下午2点")
            
            # 结束语
            closing = template['closing']
            
            # 组合完整话术
            message = f"{greeting}\n\n{match_info}\n\n{action}\n\n{closing}"
            
            # 添加匹配详情（可选）
            if match_result.matched_skills:
                message += f"\n\n匹配技能：{', '.join(match_result.matched_skills)}"
            
            logger.info(f"生成话术完成，匹配等级: {match_result.level.value}")
            return message
            
        except Exception as e:
            logger.error(f"话术生成失败: {e}")
            return "抱歉，话术生成失败，请稍后重试。"


# 创建全局实例
config_manager = RecruitmentConfig()
resume_parser = EnhancedResumeParser()
job_matcher = EnhancedJobMatcher(config_manager)
message_generator = EnhancedMessageGenerator()


# LangChain工具定义
@tool(description="解析求职者简历，提取关键信息（如工作年限、技能标签、项目经验）。输入参数：求职者简历文本（字符串）")
def enhanced_resume_parser(resume_text: str) -> str:
    """增强版简历解析工具"""
    resume_info = resume_parser.parse_resume(resume_text)
    return json.dumps(resume_info.to_dict(), ensure_ascii=False, indent=2)


@tool(description="计算简历与目标岗位的匹配度，返回匹配分数（0-100分）及关键匹配点。输入参数：解析后的简历信息（JSON字符串）和岗位类型")
def enhanced_job_matcher(resume_json: str, job_type: str = "ai_agent_engineer") -> str:
    """增强版岗位匹配工具"""
    try:
        resume_data = json.loads(resume_json)
        resume_info = ResumeInfo(**resume_data)
        match_result = job_matcher.calculate_match(resume_info, job_type)
        
        result = {
            "score": match_result.score,
            "level": match_result.level.value,
            "matched_skills": match_result.matched_skills,
            "missing_skills": match_result.missing_skills,
            "experience_match": match_result.experience_match,
            "recommendation": match_result.recommendation,
            "confidence": match_result.confidence
        }
        
        return json.dumps(result, ensure_ascii=False, indent=2)
        
    except Exception as e:
        logger.error(f"岗位匹配失败: {e}")
        return json.dumps({"error": str(e)}, ensure_ascii=False)


@tool(description="根据匹配结果生成给求职者的沟通话术。输入参数：匹配结果信息（JSON字符串）和岗位标题")
def enhanced_message_generator(match_result_json: str, job_title: str = "AI Agent开发工程师") -> str:
    """增强版话术生成工具"""
    try:
        match_data = json.loads(match_result_json)
        match_result = MatchResult(
            score=match_data["score"],
            level=MatchLevel(match_data["level"]),
            matched_skills=match_data["matched_skills"],
            missing_skills=match_data["missing_skills"],
            experience_match=match_data["experience_match"],
            recommendation=match_data["recommendation"],
            confidence=match_data["confidence"]
        )
        
        return message_generator.generate_message(match_result, job_title)
        
    except Exception as e:
        logger.error(f"话术生成失败: {e}")
        return "抱歉，话术生成失败，请稍后重试。"


# 创建优化版Agent
def create_optimized_agent():
    """创建优化版招聘助手Agent"""
    
    # 工具列表
    tools = [enhanced_resume_parser, enhanced_job_matcher, enhanced_message_generator]
    
    # 优化版提示词模板
    prompt_template = """
你是Boss直聘的「智能招聘助手」，负责处理求职者的岗位咨询。请严格按照以下流程执行：

1. 使用enhanced_resume_parser工具解析求职者简历，获取结构化信息
2. 使用enhanced_job_matcher工具计算匹配度，传入解析结果和岗位类型
3. 使用enhanced_message_generator工具生成沟通话术，传入匹配结果和岗位标题

重要说明：
- 所有工具调用必须使用JSON格式：```json{{"name":"工具名","parameters":{{"参数名":"参数值"}}}}```
- 岗位类型默认为"ai_agent_engineer"，如需其他岗位请明确指定
- 确保工具调用的参数格式正确
- 最终返回完整的沟通话术

可用工具：{tools}

用户输入：{input}
"""
    
    # 创建提示词模板
    prompt = PromptTemplate(
        template=prompt_template,
        input_variables=["tools", "input"],
        partial_variables={"tools": "\n".join([f"{t.name}: {t.description}" for t in tools])}
    )
    
    # 初始化LLM
    llm = init_chat_model("deepseek-chat", model_provider="deepseek")
    
    # 创建ZeroShotAgent
    agent = ZeroShotAgent.from_llm_and_tools(
        llm=llm,
        tools=tools,
        prompt=prompt,
        verbose=True,
    )
    
    # 创建Agent执行器
    agent_executor = AgentExecutor(
        agent=agent,
        tools=tools,
        verbose=True,
        handle_parsing_errors=True,
        max_iterations=5,
        return_intermediate_steps=True
    )
    
    return agent_executor


# 测试函数
def test_optimized_agent():
    """测试优化版Agent"""
    
    # 创建Agent
    agent_executor = create_optimized_agent()
    
    # 测试用例1：高匹配度简历
    resume_high_match = """
    姓名：张三
    工作经验：5年
    技能：Python、LangChain、Agent开发、大模型微调、RAG
    项目：主导开发过企业级AI客服Agent系统，使用LangChain实现工具调用逻辑
    教育背景：计算机科学硕士
    """
    
    # 测试用例2：中等匹配度简历
    resume_medium_match = """
    姓名：李四
    工作经验：3年
    技能：Python、Django、MySQL、基础机器学习
    项目：参与开发电商后台管理系统，负责订单模块
    """
    
    # 测试用例3：低匹配度简历
    resume_low_match = """
    姓名：王五
    工作经验：1年
    技能：Java、SpringBoot、MySQL
    项目：参与开发企业OA系统
    """
    
    test_cases = [
        ("高匹配简历", resume_high_match),
        ("中等匹配简历", resume_medium_match),
        ("低匹配简历", resume_low_match)
    ]
    
    for case_name, resume_text in test_cases:
        print(f"\n{'='*50}")
        print(f"测试用例: {case_name}")
        print(f"{'='*50}")
        
        try:
            result = agent_executor.invoke({"input": resume_text})
            print(f"最终沟通话术：\n{result['output']}")
            
            # 显示中间步骤（如果有）
            if 'intermediate_steps' in result:
                print(f"\n执行步骤：{len(result['intermediate_steps'])}步")
                
        except Exception as e:
            print(f"测试失败: {e}")


if __name__ == "__main__":
    # 运行测试
    test_optimized_agent()
